/*
 * Copyright 2009 Johnson Consulting Services
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.johnsoncs.gwt.widgets.server.export.impl;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import au.com.bytecode.opencsv.CSVWriter;

import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportException;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRequest;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.MappedExportRequest;
import com.johnsoncs.gwt.widgets.client.util.Callback;
import com.johnsoncs.gwt.widgets.server.export.ExportModel;
import com.johnsoncs.gwt.widgets.server.export.ExportStorage;
import com.johnsoncs.gwt.widgets.server.export.MappedExportFormat;
import com.johnsoncs.gwt.widgets.server.export.RowMapper;

/**
 * Abstract class capable of exporting rows to a delimited format
 * @author wilj
 *
 * @param <T> the generic type with which the table structure is associated
 */
public abstract class DelimitedExporter<T> extends MappedExportFormat<T> {
	private static final long serialVersionUID = 1L;

	private final char delimiter;
	private final String lineTerminator;

	/**
	 * Creates a new DelimitedExporter
	 * @param delimiter the character delimiter to use for fields
	 * @param lineTerminator the line terminator
	 */
	public DelimitedExporter(final char delimiter, final String lineTerminator) {
		super();
		this.delimiter = delimiter;
		this.lineTerminator = lineTerminator;
	}

	/* (non-Javadoc)
	 * @see com.johnsoncs.gwt.widgets.server.export.ExportFormat#export(java.lang.String, com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRequest, com.johnsoncs.gwt.widgets.server.export.ExportModel, com.johnsoncs.gwt.widgets.server.export.ExportStorage)
	 */
	@Override
	public String export(final String exportId, final ExportRequest<T> request, final ExportModel<T> model,
			final ExportStorage storage)
			throws ExportException {
		try {
			final Map<String, String> columns = ((MappedExportRequest<T>) request).getColumns();
			final String fileName = "export" + exportId + "." + getFileExtension();
			final OutputStream out = storage.initExportResult(fileName);
			final CSVWriter w = new CSVWriter(new OutputStreamWriter(out), delimiter,
					CSVWriter.DEFAULT_QUOTE_CHARACTER, lineTerminator);

			final RowMapper<T> mapper = getRowMapper();
			try {
				model.export(request, new Callback<T>() {
					private boolean headersWritten = false;

					@Override
					public void exec(final T value) {
						final LinkedHashMap<String, String> record = mapper.map(value, columns);
						final String[] buf = new String[record.size()];
						if (!headersWritten) {
							int idx = 0;
							for (final String key : record.keySet()) {
								buf[idx] = key;
								idx++;
							}
							w.writeNext(buf);
							headersWritten = true;
						}
						int idx = 0;
						for (final Entry<String, String> entry : record.entrySet()) {
							buf[idx] = entry.getValue();
							idx++;
						}
						w.writeNext(buf);
					}
				});
			} finally {
				w.flush();
				w.close();
				storage.finalizeExportResult(fileName);
			}
			return fileName;

		} catch (final IOException e) {
			throw new ExportException("Error exporting file", e);
		}
	}

}
